1   /*
2    * Copyright (C) 2009 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import static com.google.common.base.Preconditions.checkNotNull;
20  
21  import java.util.Collections;
22  import java.util.Map;
23  import java.util.Set;
24  
25  import javax.annotation.Nullable;
26  
27  /**
28   * GWT implementation of {@link ImmutableMap} that forwards to another map.
29   *
30   * @author Hayward Chan
31   */
32  public abstract class ForwardingImmutableMap<K, V> extends ImmutableMap<K, V> {
33  
34    final transient Map<K, V> delegate;
35  
36    ForwardingImmutableMap(Map<? extends K, ? extends V> delegate) {
37      this.delegate = Collections.unmodifiableMap(delegate);
38    }
39  
40    @SuppressWarnings("unchecked")
41    ForwardingImmutableMap(Entry<? extends K, ? extends V>... entries) {
42      Map<K, V> delegate = Maps.newLinkedHashMap();
43      for (Entry<? extends K, ? extends V> entry : entries) {
44        K key = checkNotNull(entry.getKey());
45        V previous = delegate.put(key, checkNotNull(entry.getValue()));
46        if (previous != null) {
47          throw new IllegalArgumentException("duplicate key: " + key);
48        }
49      }
50      this.delegate = Collections.unmodifiableMap(delegate);
51    }
52  
53    boolean isPartialView() {
54      return false;
55    }
56  
57    public final boolean isEmpty() {
58      return delegate.isEmpty();
59    }
60  
61    public final boolean containsKey(@Nullable Object key) {
62      return Maps.safeContainsKey(delegate, key);
63    }
64  
65    public final boolean containsValue(@Nullable Object value) {
66      return delegate.containsValue(value);
67    }
68  
69    public V get(@Nullable Object key) {
70      return (key == null) ? null : Maps.safeGet(delegate, key);
71    }
72  
73    @Override ImmutableSet<Entry<K, V>> createEntrySet() {
74      return ImmutableSet.unsafeDelegate(
75          new ForwardingSet<Entry<K, V>>() {
76            @Override protected Set<Entry<K, V>> delegate() {
77              return delegate.entrySet();
78            }
79            @Override public boolean contains(Object object) {
80              if (object instanceof Entry<?, ?>
81                  && ((Entry<?, ?>) object).getKey() == null) {
82                return false;
83              }
84              try {
85                return super.contains(object);
86              } catch (ClassCastException e) {
87                return false;
88              }
89            }
90            @Override public <T> T[] toArray(T[] array) {
91              T[] result = super.toArray(array);
92              if (size() < result.length) {
93                // It works around a GWT bug where elements after last is not
94                // properly null'ed.
95                result[size()] = null;
96              }
97              return result;
98            }
99          });
100   }
101 
102   @Override ImmutableSet<K> createKeySet() {
103     return ImmutableSet.unsafeDelegate(delegate.keySet());
104   }
105 
106   @Override ImmutableCollection<V> createValues() {
107     return ImmutableCollection.unsafeDelegate(delegate.values());
108   }
109 
110   @Override public int size() {
111     return delegate.size();
112   }
113 
114   @Override public boolean equals(@Nullable Object object) {
115     return delegate.equals(object);
116   }
117 
118   @Override public int hashCode() {
119     return delegate.hashCode();
120   }
121 
122   @Override public String toString() {
123     return delegate.toString();
124   }
125 }